package com.zyg.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.zyg.common.utils.IdWorker;
import com.zyg.seckill.controller.SeckillOrderController;
import com.zyg.seckill.entity.SeckillStatus;
import com.zyg.seckill.entity.StatusCode;
import com.zyg.seckill.entity.TbSeckillGoods;
import com.zyg.seckill.entity.TbSeckillOrder;
import com.zyg.seckill.service.TbSeckillGoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * ------------------------------
 * 功能：
 * 作者：WF
 * 微信：hbxfwf13590332912
 * 创建时间：2021/11/29-15:14
 * ------------------------------
 */
@Component
public class MultiThreadingCreateOrder {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private TbSeckillGoodsService goodsService;
    //1. 异步下单
    @Async
    public void createOrder() {
        //1.1 从右侧弹出订单队列信息，以保证有序性
        String orderQueue = redisTemplate.boundListOps("SeckillOrderQueue").rightPop();
        //1.2 转换为SeckillStatus
        SeckillStatus seckillStatus = JSON.parseObject(orderQueue, SeckillStatus.class);

        //1.3 从redis中的key为SeckillGoodsCountList_商品id为右侧弹出一个商品(避免重复超卖)
        String s = redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillStatus.getSecKillId()).rightPop();
        if(s == null){   //如果出现异常，就证明商品销售一空，清空排队的队列，及前面的用户队列的备份
           clearQueue(seckillStatus.getUsername());
           return;
        }

        //1.4 查询出秒杀的商品信息
        Long secKillId = seckillStatus.getSecKillId();      //秒杀商品id
        String time = seckillStatus.getTime();              //秒杀的是时间段
        BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps("seckillGoods_" + time);
        String seckillStr = boundHashOperations.get(secKillId + "");
        TbSeckillGoods seckillGoods = JSON.parseObject(seckillStr, TbSeckillGoods.class);

        //1.5 判断秒杀商品是否存在
        if(seckillGoods == null || seckillGoods.getStockCount() == 0){
            throw new RuntimeException("商品己售罄");
        }

        //1.6 构造秒杀订单对象
        TbSeckillOrder seckillOrder = new TbSeckillOrder();
        long id = idWorker.nextId();
        seckillOrder.setId(new Integer(id + ""));
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setMoney(seckillGoods.getCostPrice());
        seckillOrder.setStatus("0");            //未支付
        seckillOrder.setUserId(seckillStatus.getUsername());
        seckillOrder.setSeckillId(new Integer(seckillStatus.getSecKillId() + ""));
        //1.7 保存秒杀订单到redis中
        redisTemplate.boundHashOps("SeckillOrder").put(seckillStatus.getUsername(),JSON.toJSONString(seckillOrder));

        //1.8 扣减库存(精准扣减)
        Long stockCount = redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillStatus.getSecKillId()+"", -1);
        seckillGoods.setStockCount(new Integer(stockCount + ""));

        //1.9 其它情况,处理兼容性问题
        if(seckillGoods.getStockCount() <= 0){
            //1.9.1 将商品改回到数据库中
            goodsService.updateById(seckillGoods);
            //1.9.2 从redis中删除此商品
            redisTemplate.boundHashOps("seckillGoods_" + time).delete(seckillGoods.getId() + "");
        }else{      //1.9.3 如果库存还有，就重新设置回redis
            redisTemplate.boundHashOps("seckillGoods_" + time).put(seckillGoods.getId()+"",JSON.toJSONString(seckillGoods));
        }

        //1.10 重新修改支付备份状态
        seckillStatus.setMoney(seckillGoods.getCostPrice().floatValue());       //修改订单金额
        seckillStatus.setStatus(2);     //代表正在等待支付
        seckillStatus.setOrderId(id);    //订单id
        redisTemplate.boundHashOps("UserQueueStatus").put(seckillStatus.getUsername(),JSON.toJSONString(seckillStatus));


        //放一个登录名到redis中，为后面支付宝异步回调做准备
        redisTemplate.opsForValue().set(seckillOrder.getId()+"",seckillStatus.getUsername());
    }

    private void clearQueue(String username) {
        //1. 清理排队的数量
        redisTemplate.boundHashOps("UserQueueCount").delete(username);
        //2. 清除排队的状态值
        redisTemplate.boundHashOps("UserQueueStatus").delete(username);
    }
}
